package gestorBD;

import excepciones.*;
import gestorbienraizok.contratos.Arrendamiento;
import gestorbienraizok.contratos.Compraventa;
import gestorbienraizok.inmuebles.Apartamento;
import gestorbienraizok.inmuebles.Banho;
import gestorbienraizok.inmuebles.Casa;
import gestorbienraizok.inmuebles.Garaje;
import gestorbienraizok.inmuebles.Inmueble;
import gestorbienraizok.inmuebles.Pieza;
import gestorbienraizok.inmuebles.ServiciosAdicionales;
import gestorbienraizok.inmuebles.Torre;
import gestorbienraizok.inmuebles.Unidad;
import gestorbienraizok.usuarios.Administrador;
import gestorbienraizok.usuarios.Cita;
import gestorbienraizok.usuarios.Cliente;
import gestorbienraizok.usuarios.ClienteAnonimo;
import gestorbienraizok.usuarios.ClienteDemandador;
import gestorbienraizok.usuarios.ClienteOferente;
import gestorbienraizok.usuarios.Funcionario;
import gestorbienraizok.usuarios.FuncionarioJefe;
import gestorbienraizok.usuarios.Persona;
import gestorbienraizok.usuarios.Seguridad;
import java.text.DecimalFormat;
import java.util.LinkedList;
import uiMain.MenuDeOpciones;

public class Controlador {

    private static LinkedList<Unidad> listaDeUnidades = new LinkedList();
    private static LinkedList<Persona> listaDePersonas = new LinkedList();
    private static LinkedList<ClienteAnonimo> listaDeClientesAnonimos = new LinkedList();
    private static Persona usuarioActual;

    public static LinkedList<Persona> getListaDePersonas() {
        return listaDePersonas;
    }

    public static LinkedList<Unidad> getListaDeUnidades() {
        return listaDeUnidades;
    }

    public static LinkedList<ClienteAnonimo> getListaDeClientesAnonimos() {
        return listaDeClientesAnonimos;
    }

    public static void cargarXML() throws NoSeEncontroXMLExcepcion {
        LinkedList<LinkedList> listaDeTodo = (LinkedList<LinkedList>) Persistor.leerDesdeXml("./Base-de-datos/database.xml");
        if (listaDeTodo != null) {
            listaDeUnidades = listaDeTodo.get(0);
            listaDePersonas = listaDeTodo.get(1);
            listaDeClientesAnonimos = listaDeTodo.get(2);
        } else {
            throw new NoSeEncontroXMLExcepcion();
        }

    }

    public static void guardarXML() {
        LinkedList<LinkedList> listaDeTodo = new LinkedList();
        listaDeTodo.add(listaDeUnidades);
        listaDeTodo.add(listaDePersonas);
        listaDeTodo.add(listaDeClientesAnonimos);

        Persistor.guardarEnXml("./Base-de-datos/database.xml", listaDeTodo);
    }

    public static void cargarCasosDePrueba() {
        //CASOS DE PRUEBA
        Administrador administrador1 = new Administrador(101010, "25bfa978c824924d474de5706e3d98a29bea4b193aab9c6b4c460382d56991e0a7e6325dec579ba1337b79a4d346ca78add4e3f48cab2adc5dda8a55f59056ab", "Yennifer Marcela Tobón");
        listaDePersonas.add(administrador1);

        FuncionarioJefe funcionarioJefe1 = new FuncionarioJefe(1152447369, "25bfa978c824924d474de5706e3d98a29bea4b193aab9c6b4c460382d56991e0a7e6325dec579ba1337b79a4d346ca78add4e3f48cab2adc5dda8a55f59056ab", "Nicolás Henao Arango", 3500000);
        listaDePersonas.add(funcionarioJefe1);

        Funcionario funcionario1 = new Funcionario(202020, "25bfa978c824924d474de5706e3d98a29bea4b193aab9c6b4c460382d56991e0a7e6325dec579ba1337b79a4d346ca78add4e3f48cab2adc5dda8a55f59056ab", "Simón Palacio", 1300000);
        listaDePersonas.add(funcionario1);
        funcionarioJefe1.registrarSubordinado(funcionario1);

        ClienteOferente clienteOferente1 = new ClienteOferente(new Cliente(1040742678, "Juan Diego Merino", "Calle 30 #12-10", 3522659, 3163237562L, (byte) 4));
        listaDePersonas.add(clienteOferente1);

        ClienteOferente clienteOferente2 = new ClienteOferente(new Cliente(303030, "Daniel Henao Rúa", "Tr 72B #69-36", 4112756, 3128674512L, (byte) 4));
        listaDePersonas.add(clienteOferente2);

        ClienteDemandador clienteDemandador1 = new ClienteDemandador(new Cliente(404040, "Beatriz Moreno Soto", "Cl 19S #23-75", 2665628, 3148872121L, (byte) 4), 45000000, "Sur", (byte) 5, "Ninguna");
        funcionario1.anhadirALaLista(clienteDemandador1);
        listaDePersonas.add(clienteDemandador1);

        ClienteDemandador clienteDemandador2 = new ClienteDemandador(new Cliente(505050, "Alejandro Ramírez", "Cr 76 #38-22", 3162327, 3105458323L, (byte) 4), 5000000, "Cualquiera", (byte) 3, "Ninguna");
        funcionario1.anhadirALaLista(clienteDemandador2);
        listaDePersonas.add(clienteDemandador2);

        ServiciosAdicionales serviciosAdicionales1 = new ServiciosAdicionales(false, false, true, true, true, false, true);
        ServiciosAdicionales serviciosAdicionales2 = new ServiciosAdicionales(true, true, false, false, false, true, false);
        ServiciosAdicionales serviciosAdicionales3 = new ServiciosAdicionales(false, false, false, false, false, true, true);

        Unidad unidad1 = new Unidad("U0", "Parcelación Alcazar", "Cr 37A #1-S 138", (byte) 4, true, serviciosAdicionales1);
        listaDeUnidades.add(unidad1);
        Casa casa1 = new Casa("C0", (byte) 3);
        unidad1.agregarCasa(casa1);
        clienteOferente1.anhadirInmueble(casa1);//Cliente Juan Diego Merino
        casa1.setRol((byte) 1);//Solo venta
        casa1.setDisponibilidad((byte) 3);
        casa1.setPrecioDeVenta(210000000);
        casa1.setTarifaDeArrendamiento(0);
        casa1.setAreaTotal(184);
        casa1.setPatio(true);
        casa1.anhadirCuarto(new Banho(10, true, true, false, true));
        casa1.anhadirCuarto(new Banho(6, false, false, false, true));
        casa1.anhadirCuarto(new Pieza(12, "Comedor"));
        casa1.anhadirCuarto(new Pieza(20, "Cocina"));
        casa1.anhadirCuarto(new Pieza(8, "Estar"));
        casa1.anhadirGaraje(new Garaje(17, 2, true));

        Unidad unidad2 = new Unidad("U1", "Ed. Castilla", "Tv 5D #39-24", (byte) 3, true, serviciosAdicionales2);
        listaDeUnidades.add(unidad2);
        Torre torre1DeUnidad2 = new Torre((byte) 1, (byte) 8, (byte) 2, 2);
        unidad2.agregarTorre(torre1DeUnidad2);
        Apartamento apto1 = new Apartamento("A0", 2);
        torre1DeUnidad2.agregarApartamento(apto1);
        clienteOferente1.anhadirInmueble(apto1);
        apto1.setRol((byte) 3);//Venta y arriendo
        apto1.setPrecioDeVenta(52000000);
        apto1.setTarifaDeArrendamiento(470000);
        apto1.setAreaTotal(65);
        apto1.setPatio(true);
        apto1.anhadirCuarto(new Banho(10, true, true, false, false));
        apto1.anhadirCuarto(new Banho(14, false, true, true, true));
        apto1.anhadirCuarto(new Banho(6, false, false, false, true));
        apto1.anhadirCuarto(new Pieza(12, "Biblioteca"));
        apto1.anhadirCuarto(new Pieza(7, "Alcoba"));
        apto1.anhadirCuarto(new Pieza(23, "Vestier"));
        apto1.anhadirCuarto(new Pieza(26, "Cocina"));
        apto1.anhadirCuarto(new Pieza(14, "Comedor"));

        Unidad unidad3 = new Unidad("U2", "Altos de la Castellana", "Cra 84 #33-01", (byte) 5, true, serviciosAdicionales3);
        listaDeUnidades.add(unidad3);
        Torre torre5DeUnidad3 = new Torre((byte) 5, (byte) 16, (byte) 4, 1);
        Torre torre6DeUnidad3 = new Torre((byte) 6, (byte) 20, (byte) 4, 2);
        unidad3.agregarTorre(torre5DeUnidad3);
        unidad3.agregarTorre(torre6DeUnidad3);
        Apartamento apto2 = new Apartamento("A1", 6);
        torre5DeUnidad3.agregarApartamento(apto2);
        clienteOferente1.anhadirInmueble(apto2);
        apto2.setRol((byte) 2);//Solo arriendo
        apto2.setPrecioDeVenta(0);
        apto2.setTarifaDeArrendamiento(1250000);
        apto2.setAreaTotal(78);
        apto2.setPatio(false);
        apto2.anhadirCuarto(new Banho(6, true, true, false, false));
        apto2.anhadirCuarto(new Banho(24, false, false, false, true));
        apto2.anhadirCuarto(new Banho(11, false, true, true, true));
        apto2.anhadirCuarto(new Banho(9, true, true, true, false));
        apto2.anhadirCuarto(new Pieza(13, "Biblioteca"));
        apto2.anhadirCuarto(new Pieza(18, "Comedor"));

        Apartamento apto3 = new Apartamento("A2", 2);
        torre6DeUnidad3.agregarApartamento(apto3);
        clienteOferente2.anhadirInmueble(apto3);
        apto3.setRol((byte) 4);//No disponible
        apto3.setPrecioDeVenta(0);
        apto3.setTarifaDeArrendamiento(0);
        apto3.setAreaTotal(78);
        apto3.setPatio(false);
        apto3.anhadirCuarto(new Banho(6, true, true, false, false));
        apto3.anhadirCuarto(new Banho(24, false, false, false, true));
        apto3.anhadirCuarto(new Banho(11, false, true, true, true));
        apto3.anhadirCuarto(new Banho(9, true, true, true, false));
        apto3.anhadirCuarto(new Pieza(13, "Biblioteca"));
        apto3.anhadirCuarto(new Pieza(18, "Comedor"));

        Casa casa2 = new Casa("C1", (byte) 2);
        unidad3.agregarCasa(casa2);
        clienteOferente2.anhadirInmueble(casa2);
        casa2.setRol((byte) 2);//Solo arriendo
        casa2.setPrecioDeVenta(0);
        casa2.setTarifaDeArrendamiento(1700000);
        casa2.setAreaTotal(205);
        casa2.setPatio(true);
        casa2.anhadirCuarto(new Banho(10, false, false, false, true));
        casa2.anhadirCuarto(new Banho(17, true, true, false, true));
        casa2.anhadirCuarto(new Banho(7, false, false, false, false));
        casa2.anhadirCuarto(new Pieza(35, "Sala"));
        casa2.anhadirCuarto(new Pieza(20, "Alcoba"));
        casa2.anhadirGaraje(new Garaje(23, 3, true));
        casa2.anhadirGaraje(new Garaje(14, 2, false));

    }

    public static boolean registrarCita(String nombreDelInvitado, byte motivoCita, long cedulaDelInvitado) {

        Cita nuevaCita = new Cita(cedulaDelInvitado, motivoCita);
        Funcionario esteFuncionario = Funcionario.funcionarioAleatorio();
        ClienteAnonimo nuevoClienteAnonimo = new ClienteAnonimo(cedulaDelInvitado, nombreDelInvitado);
        String horaDeLaCita = esteFuncionario.proximaCitaDisponible(nuevaCita);
        if (!horaDeLaCita.equals("")) {//Si se pudo asignar la cita a algun funcinoario
            listaDeClientesAnonimos.add(nuevoClienteAnonimo);
            return true;
        } else {
            for (int i = 0; i < listaDePersonas.size(); i++) {
                Persona estaPersona = listaDePersonas.get(i);
                if (estaPersona instanceof Funcionario) {
                    esteFuncionario = (Funcionario) estaPersona;
                    horaDeLaCita = esteFuncionario.proximaCitaDisponible(nuevaCita);
                    if (!horaDeLaCita.equals("")) {
                        listaDeClientesAnonimos.add(nuevoClienteAnonimo);
                        return true;
                    }
                }
            }
            return false;
        }
    }

    public static byte comprobarCedula(long cedula) {
        /*Códigos de error:
         0 si la persona buscada no está en el sistema de ninguna forma
         1 si la persona buscada es cliente anonimo, es decir, ya tiene cita asignada
         2 si la persona buscada ya está en el sistema (cliente, funcionario, admin...)
         */

        for (int i = 0; i < listaDeClientesAnonimos.size(); i++) {
            ClienteAnonimo esteClienteAnonimo = listaDeClientesAnonimos.get(i);
            if (esteClienteAnonimo.getCedula() == cedula) {
                return 1;//Porque ya tiene cita
            }
        }

        for (int i = 0; i < listaDePersonas.size(); i++) {
            Persona estaPersona = listaDePersonas.get(i);
            if (estaPersona.getCedula() == cedula) {
                return 2;//Porque es alguien en el sistema
            }
        }

        return 0;//No hay nadie con esa cedula
    }

    public static String recordarCita(long cedula) {
        for (int i = 0; i < listaDePersonas.size(); i++) {
            Persona estaPersona = listaDePersonas.get(i);
            if (estaPersona instanceof Funcionario) {
                Funcionario esteFuncionario = (Funcionario) estaPersona;
                Cita[] listaDeCitas = esteFuncionario.getListaDeCitas();
                for (int j = 0; j < 16; j++) {
                    Cita estaCita = listaDeCitas[j];
                    if (estaCita != null) {
                        ClienteAnonimo esteClienteAnonimo = estaCita.getClienteAnonimo();
                        if (esteClienteAnonimo.getCedula() == cedula) {
                            String[] nombreHoras = {"8:00 am", "8:30 am", "9:00 am", "9:30 am", "10:00 am", "10:30 am", "11:00 am", "11:30 am", "2:00 pm", "2:30 pm", "3:00 pm", "3:30 pm", "4:00 pm", "4:30 pm", "5:00 pm", "5:30 pm"};
                            return "Usted tiene una cita con el funcionario " + esteFuncionario.getNombre() + " a las " + nombreHoras[j];
                        }
                    }
                }
            }
        }
        return "Usted no tiene asignada ninguna cita";
    }

    public static boolean iniciarSesionComoAdministrador(long cedula, String contrasenha) {
        contrasenha = Seguridad.hacerHash(contrasenha);
        for (int i = 0; i < listaDePersonas.size(); i++) {
            Persona estaPersona = listaDePersonas.get(i);
            if (cedula == estaPersona.getCedula()) {
                if (estaPersona.getContrasenha().equals(contrasenha) && estaPersona instanceof Administrador) {
                    usuarioActual = estaPersona;
                    return true;
                } else {
                    return false;//Si la contraseña es incorrecta o si no es un administrador
                }
            }
        }
        return false;//Si el usuario no existe
    }

    public static boolean iniciarSesionComoFuncionario(long cedula, String contrasenha) {
        contrasenha = Seguridad.hacerHash(contrasenha);
        for (int i = 0; i < listaDePersonas.size(); i++) {
            Persona estaPersona = listaDePersonas.get(i);
            if (cedula == estaPersona.getCedula()) {
                if (estaPersona.getContrasenha().equals(contrasenha) && estaPersona instanceof Funcionario) {
                    usuarioActual = estaPersona;
                    return true;
                } else {
                    return false;//Si la contraseña es incorrecta o si no es un funcionario
                }
            }
        }
        return false;//Si el usuario no existe
    }

    public static String[][] obtenerTablaDeClientesDemandantes() {
        Funcionario esteFuncionario = (Funcionario) usuarioActual;
        String[][] tabla = esteFuncionario.tablaDeClientesDemandantes();
        return tabla;
    }

    public static boolean registrarNuevoClienteDemandante(long cedula, String nombre, String direccion, long telefono, long celular, long presupuesto, String lugar, byte estrato, String preferencias) {
        if (Persona.buscarPersona(cedula) == null) {
            Cliente nuevoCliente = new Cliente(cedula, nombre, direccion, telefono, celular);
            ClienteDemandador nuevoClienteDemandador = new ClienteDemandador(nuevoCliente, presupuesto, lugar, estrato, preferencias);
            listaDePersonas.add(nuevoClienteDemandador);
            Funcionario esteFuncionario = (Funcionario) usuarioActual;
            esteFuncionario.anhadirALaLista(nuevoClienteDemandador);
            return true;
        }
        return false;
    }

    public static boolean registrarNuevoClienteOferente(long cedula, String nombre, String direccion, long telefono, long celular) {
        if (Persona.buscarPersona(cedula) == null) {
            Cliente nuevoCliente = new Cliente(cedula, nombre, direccion, telefono, celular);
            ClienteOferente nuevoClienteOferente = new ClienteOferente(nuevoCliente);
            listaDePersonas.add(nuevoClienteOferente);
            return true;
        }
        return false;
    }

    public static boolean cambiarContrasenha(String contrasenhaActualIngresada, String contrasenhaNuevaIngresada) {
        Persona esteUsuario = usuarioActual;
        contrasenhaActualIngresada = Seguridad.hacerHash(contrasenhaActualIngresada);

        if (contrasenhaActualIngresada.equals(esteUsuario.getContrasenha())) {
            contrasenhaNuevaIngresada = Seguridad.hacerHash(contrasenhaNuevaIngresada);
            esteUsuario.setContrasenha(contrasenhaNuevaIngresada);
            return true;
        } else {
            return false;
        }
    }

    public static void limpiarCookie() {
        usuarioActual = null;
    }

    public static Object[] obtenerListaDeOpciones() {
        LinkedList listaDeOpciones = usuarioActual.getMenu().getListaOpciones();
        Object[] opcionesDeMenu = listaDeOpciones.toArray();
        return opcionesDeMenu;
    }

    public static String[][] obtenerPago(byte mes, int anho) {
        Funcionario esteFuncionario = (Funcionario) usuarioActual;

        float[] comisionPorVentas = {0};
        float[] comisionPorArrendamientos = {0};

        esteFuncionario.calcularSalario(mes, anho, comisionPorVentas, comisionPorArrendamientos);

        String[][] tablaRespuesta = new String[4][2];
        float salarioBase = esteFuncionario.getSalarioBase();
        tablaRespuesta[0][0] = "Salario base";
        tablaRespuesta[0][1] = formatearPrecio(salarioBase);

        tablaRespuesta[1][0] = "Comisión por ventas";
        tablaRespuesta[1][1] = formatearPrecio(comisionPorVentas[0]);

        tablaRespuesta[2][0] = "Comisión por arrendamientos";
        tablaRespuesta[2][1] = formatearPrecio(comisionPorArrendamientos[0]);

        tablaRespuesta[3][0] = "TOTAL";
        tablaRespuesta[3][1] = formatearPrecio(salarioBase + comisionPorVentas[0] + comisionPorArrendamientos[0]);

        return tablaRespuesta;
    }

    public static String[][] obtenerListaDeClientesDeSubordinados() {

        FuncionarioJefe esteFuncionarioJefe = (FuncionarioJefe) usuarioActual;
        int totalFilas = 0;
        for (int i = 0; i < esteFuncionarioJefe.getListaDeCedulasDeSubordinados().size(); i++) {
            long cedulaDeEsteSubordinado = esteFuncionarioJefe.getListaDeCedulasDeSubordinados().get(i);
            Funcionario esteSubordinado = (Funcionario) Persona.buscarPersona(cedulaDeEsteSubordinado);

            if (esteSubordinado.getListaDeCedulasDeClientesDemandantes().size() == 0) {
                totalFilas++;
            } else {
                totalFilas += esteSubordinado.getListaDeCedulasDeClientesDemandantes().size();
            }
        }

        int cursor = 0;
        String[][] t = new String[totalFilas][4];

        if (esteFuncionarioJefe.getListaDeCedulasDeSubordinados().size() != 0) {

            for (int i = 0; i < esteFuncionarioJefe.getListaDeCedulasDeSubordinados().size(); i++) {
                long cedulaDeEsteSubordinado = esteFuncionarioJefe.getListaDeCedulasDeSubordinados().get(i);
                Funcionario esteSubordinado = (Funcionario) Persona.buscarPersona(cedulaDeEsteSubordinado);

                if (esteSubordinado.getListaDeCedulasDeClientesDemandantes().size() == 0) {
                    t[cursor][0] = esteSubordinado.getNombre();
                    t[cursor][1] = String.valueOf(esteSubordinado.getCedula());
                    cursor++;
                }

                for (int j = 0; j < esteSubordinado.getListaDeCedulasDeClientesDemandantes().size(); j++) {
                    t[cursor][0] = esteSubordinado.getNombre();
                    t[cursor][1] = String.valueOf(esteSubordinado.getCedula());
                    Persona esteClienteDemandante = (ClienteDemandador) Persona.buscarPersona(esteSubordinado.getListaDeCedulasDeClientesDemandantes().get(j));
                    t[cursor][2] = esteClienteDemandante.getNombre();
                    t[cursor][3] = String.valueOf(esteClienteDemandante.getCedula());
                    cursor++;
                }

            }
        } else {
            t = new String[1][1];
            t[0][0] = "Usted no tiene subordinados";
        }

        return t;
    }

    public static String[][] obtenerSubordinados() {
        FuncionarioJefe esteFuncionarioJefe = (FuncionarioJefe) usuarioActual;

        String[][] t = new String[esteFuncionarioJefe.getListaDeCedulasDeSubordinados().size()][2];

        if (esteFuncionarioJefe.getListaDeCedulasDeSubordinados().size() != 0) {

            for (int i = 0; i < esteFuncionarioJefe.getListaDeCedulasDeSubordinados().size(); i++) {
                long cedulaDeEsteSubordinado = esteFuncionarioJefe.getListaDeCedulasDeSubordinados().get(i);
                Funcionario esteSubordinado = (Funcionario) Persona.buscarPersona(cedulaDeEsteSubordinado);

                t[i][0] = esteSubordinado.getNombre();
                t[i][1] = String.valueOf(esteSubordinado.getCedula());
            }

        } else {
            t = new String[1][1];
            t[0][0] = "Usted no tiene subordinados";
        }

        return t;
    }

    public static String obtenerInformacionDelUsuario() {
        return usuarioActual.toString();
    }

    public static String obtenerSiguienteCodigoDeCasa() {
        return "C" + Casa.getNumeroDeCasasRegistradas();
    }

    public static String obtenerSiguienteCodigoDeApartamento() {
        return "A" + Apartamento.getNumeroDeApartamentosRegistrados();
    }

    public static String obtenerSiguienteCodigoDeUnidad() {
        return "U" + Unidad.getNumeroDeUnidadesRegistradas();
    }

    public static String registrarNuevoApartamento(long cedula, String codigoApto, String codigoUnidad, int numeroTorre, int numPisosTorre, int numAptosXPiso, int numAscensores, float area, int numBanhos, int numAlcobas, int numParqueaderos, byte rol, long precioDeVenta, long tarifaDeArrendamiento) {
        ClienteOferente esteClienteOferente = ClienteOferente.elClienteEstaRegistradoComoOferente(cedula);

        if (esteClienteOferente == null) {
            return "No se encuentra registrado ningún cliente oferente con cédula " + cedula;
        }

        Unidad estaUnidad = Unidad.buscarUnidad(codigoUnidad);
        if (estaUnidad == null) {
            return "No hay ninguna unidad registrada con código " + codigoUnidad;
        }

        Torre estaTorre = Torre.buscarTorre(estaUnidad, (byte) numeroTorre);
        if (estaTorre == null) {
            estaTorre = new Torre((byte) numeroTorre, (byte) numPisosTorre, (byte) numAptosXPiso, numAscensores);
            estaUnidad.agregarTorre(estaTorre);
        }

        Apartamento esteApartamento = new Apartamento(codigoApto, numParqueaderos);

        esteClienteOferente.anhadirInmueble(esteApartamento);
        esteApartamento.setAreaTotal(area);

        for (int i = 0; i < numBanhos; i++) {
            esteApartamento.anhadirCuarto(new Banho());
        }

        for (int i = 0; i < numAlcobas; i++) {
            esteApartamento.anhadirCuarto(new Pieza());
        }

        estaTorre.agregarApartamento(esteApartamento);
        ingresarRolYPrecios(esteApartamento, rol, precioDeVenta, tarifaDeArrendamiento);
        return "Se registró correctamente este apartamento. Recuerde que el código es: " + codigoApto;
    }

    public static String registrarNuevaCasa(long cedula, String codigoCasa, String codigoUnidad, int numeroPisos, float area, int numeroBanhos, int numeroAlcobas, int numeroGarajes, byte rol, long precioDeVenta, long tarifaDeArrendamiento) {
        ClienteOferente esteClienteOferente = ClienteOferente.elClienteEstaRegistradoComoOferente(cedula);

        if (esteClienteOferente == null) {
            return "No se encuentra registrado ningún cliente oferente con cédula " + cedula;
        }

        Unidad estaUnidad = Unidad.buscarUnidad(codigoUnidad);
        if (estaUnidad == null) {
            return "No hay ninguna unidad registrada con código " + codigoUnidad;
        }

        Casa estaCasa = new Casa(codigoCasa, (byte) numeroPisos);

        esteClienteOferente.anhadirInmueble(estaCasa);
        estaCasa.setAreaTotal(area);

        for (int i = 0; i < numeroBanhos; i++) {
            estaCasa.anhadirCuarto(new Banho());
        }

        for (int i = 0; i < numeroAlcobas; i++) {
            estaCasa.anhadirCuarto(new Pieza());
        }

        ingresarRolYPrecios(estaCasa, rol, precioDeVenta, tarifaDeArrendamiento);
        estaUnidad.agregarCasa(estaCasa);
        return "Se registró correctamente esta casa. Recuerde que el código es: " + codigoCasa;
    }

    public static String registrarNuevaUnidad(String codigo, String nombre, String direccion, int estrato) {
        Unidad estaUnidad = new Unidad(codigo, nombre, direccion, (byte) estrato, true, new ServiciosAdicionales());
        listaDeUnidades.add(estaUnidad);
        return "Se registró correctamente esta unidad. Reuerde que el código es " + codigo;
    }

    private static void ingresarRolYPrecios(Inmueble inmueble, byte rol, long precioDeVenta, long tarifaDeArrendamiento) {
        inmueble.setRol(rol);
        inmueble.setPrecioDeVenta(precioDeVenta);
        inmueble.setTarifaDeArrendamiento(tarifaDeArrendamiento);
    }

    public static boolean registrarNuevoFuncionario(long cedula, String nombre, String contrasenha, long salarioBase) {
        if (Persona.buscarPersona(cedula) == null) {
            Funcionario nuevoFuncionario = new Funcionario(cedula, Seguridad.hacerHash(contrasenha), nombre, salarioBase);
            listaDePersonas.add(nuevoFuncionario);
            FuncionarioJefe esteFuncionarioJefe = (FuncionarioJefe) usuarioActual;
            esteFuncionarioJefe.registrarSubordinado(nuevoFuncionario);
            return true;
        }
        return false;
    }

    public static String buscarPropiedadPorCodigo(String codigoABuscar) {
        Inmueble esteInmueble = Inmueble.buscarInmueble(codigoABuscar);

        if (esteInmueble == null) {
            return "No se encontró ninguna propiedad con código " + codigoABuscar;
        }

        boolean esApartamento = esteInmueble instanceof Apartamento;

        String textoAImprimir;

        textoAImprimir = "\nEst" + ((esApartamento) ? "e apartamento" : "a casa") + " cuenta con las siguientes características: \n\n";

        textoAImprimir += esteInmueble.toString();
        return textoAImprimir;

    }

    public static String registrarNuevoNegocioArrendamiento(String codigoInmueble, long cedulaDemandante, long precio) {
        Funcionario llamador = (Funcionario) usuarioActual;
        ClienteOferente esteClienteOferente = null;
        ClienteDemandador esteClienteDemandador = null;
        Inmueble esteInmueble = null;

        Persona estaPersona = Persona.buscarPersona(cedulaDemandante);

        if (estaPersona != null) {
            if (estaPersona instanceof ClienteDemandador) {
                esteClienteDemandador = (ClienteDemandador) estaPersona;
                if (!esteClienteDemandador.getFuncionario().equals(llamador)) {
                    return "El cliente " + esteClienteDemandador.getNombre() + " es asesorado por " + esteClienteDemandador.getFuncionario().getNombre() + ", no por usted.";
                }
            } else {
                return estaPersona.getNombre() + " está registrado pero NO es un cliente demandador";
            }
        } else {
            return "No se encontró a ningun usuario con cédula " + cedulaDemandante;
        }

        esteInmueble = Inmueble.buscarInmueble(codigoInmueble);

        if (esteInmueble == null) {
            return "No se encontró ningún inmueble con el código " + codigoInmueble.toUpperCase();
        } else {
            esteClienteOferente = esteInmueble.getPropietario();

            if (esteInmueble.obtenerRol().toLowerCase().contains("alquiler")) {
                if (!(esteInmueble.obtenerDisponibilidad().equals("Disponible"))) {
                    return "Esta propiedad no está disponible para alquiler. Ya fue " + esteInmueble.obtenerDisponibilidad().toLowerCase();
                }
            } else {
                return "Esta propiedad no está disponible para alquiler";
            }
        }

        Arrendamiento nuevoArrendamiento = new Arrendamiento(precio, esteClienteOferente.getCedula(), esteInmueble.getCodigo());
        esteClienteDemandador.getListaDeContratos().add(nuevoArrendamiento);
        esteInmueble.setDisponibilidad((byte) 2);
        esteClienteDemandador.setTieneContratos(true);
        esteClienteOferente.setTieneContratos(true);
        return "Se ha creado correctamente el contrato #" + String.format("%3d", esteClienteDemandador.getListaDeContratos().getLast().getCodigo()).replace(" ", "0");

    }

    public static String registrarNuevoNegocioVenta(String codigoInmueble, long cedulaDemandante, long precio) {
        Funcionario llamador = (Funcionario) usuarioActual;
        ClienteOferente esteClienteOferente = null;
        ClienteDemandador esteClienteDemandador = null;
        Inmueble esteInmueble = null;

        Persona estaPersona = Persona.buscarPersona(cedulaDemandante);

        if (estaPersona != null) {
            if (estaPersona instanceof ClienteDemandador) {
                esteClienteDemandador = (ClienteDemandador) estaPersona;
                if (!esteClienteDemandador.getFuncionario().equals(llamador)) {
                    return "El cliente " + esteClienteDemandador.getNombre() + " es asesorado por " + esteClienteDemandador.getFuncionario().getNombre() + ", no por usted.";
                }
            } else {
                return estaPersona.getNombre() + " está registrado pero NO es un cliente demandador";
            }
        } else {
            return "No se encontró a ningun usuario con cédula " + cedulaDemandante;
        }

        esteInmueble = Inmueble.buscarInmueble(codigoInmueble);

        if (esteInmueble == null) {
            return "No se encontró ningún inmueble con el código " + codigoInmueble.toUpperCase();
        } else {
            esteClienteOferente = esteInmueble.getPropietario();

            if (esteInmueble.obtenerRol().contains("Venta")) {
                if (!(esteInmueble.obtenerDisponibilidad().equals("Disponible"))) {
                    return "Esta propiedad no está disponible para la venta, ya fue " + esteInmueble.obtenerDisponibilidad().toLowerCase();
                }
            } else {
                return "Esta propiedad no está disponible para la venta";
            }
        }

        Compraventa nuevaCompraventa = new Compraventa(precio, esteClienteOferente.getCedula(), esteInmueble.getCodigo());
        esteClienteDemandador.getListaDeContratos().add(nuevaCompraventa);
        esteInmueble.setDisponibilidad((byte) 1);
        esteClienteDemandador.setTieneContratos(true);
        esteClienteOferente.setTieneContratos(true);
        return "Se ha creado correctamente el contrato #" + String.format("%3d", esteClienteDemandador.getListaDeContratos().getLast().getCodigo()).replace(" ", "0");

    }

    public static String obtenerTodasLasPropiedades() {
        String textoARetornar;

        textoARetornar = "\nActualmente se encuentran en el sistema las siguientes propiedades:\n\n";

        textoARetornar += "Código   Tipo          Rol                Disponibilidad\n";

        textoARetornar += "---------------------------------------------------------\n";

        textoARetornar += Unidad.getResumenCodigoTipoDeInmuebleRolDisponibilidadDeTodosLosInmueblesDeLaUnidad();
        return textoARetornar;

    }

    public static String buscarPropiedadPorCriterios(boolean esApartamento, boolean esParaArrendar, String rangoArea, String rangoEstrato, int numeroDeBanhos, int numeroDeEspacios, int numeroMinimoParqueaderos, String rangoValor) throws RangoNoValidoExcepcion {
        int areaMinima = 0;
        int areaMaxima = Integer.MAX_VALUE;
        byte estratoMinimo = 1;
        byte estratoMaximo = 6;
        long valorMinimo = 0;
        long valorMaximo = Long.MAX_VALUE;
        try {
            if (!rangoArea.equals("0")) {
                areaMinima = Integer.parseInt(rangoArea.substring(0, rangoArea.indexOf("-")));
                areaMaxima = Integer.parseInt(rangoArea.substring(rangoArea.indexOf("-") + 1));
            }

            if (!rangoEstrato.equals("0")) {
                estratoMinimo = Byte.parseByte(rangoEstrato.substring(0, rangoEstrato.indexOf("-")));
                estratoMaximo = Byte.parseByte(rangoEstrato.substring(rangoEstrato.indexOf("-") + 1));
            }

            if (!rangoValor.equals("0")) {
                valorMinimo = Long.parseLong(rangoValor.substring(0, rangoValor.indexOf("-")));
                valorMaximo = Long.parseLong(rangoValor.substring(rangoValor.indexOf("-") + 1));
            }
        } catch (Exception ex) {
            throw new RangoNoValidoExcepcion();
        }
        //Ya están recogidos todos los criterios
        LinkedList<Inmueble> listaDeInmueblesQueCumplen = new LinkedList();

        for (int i = 0; i < listaDeUnidades.size(); i++) {
            Unidad estaUnidad = listaDeUnidades.get(i);
            if (esApartamento) {
                if (estaUnidad.getNumeroDeApartamentos() != 0) {
                    for (int j = 0; j < estaUnidad.getListaDeTorres().size(); j++) {
                        Torre estaTorre = estaUnidad.getListaDeTorres().get(j);
                        for (int k = 0; k < estaTorre.getNumeroDeApartamentos(); k++) {
                            Apartamento esteApartamento = estaTorre.getListaDeApartamentos().get(k);
                            if (Apartamento.elApartamentoAplica(esteApartamento, esParaArrendar, areaMinima, areaMaxima,
                                    (byte) estratoMinimo, (byte) estratoMaximo, (byte) numeroDeBanhos, (byte) numeroDeEspacios,
                                    (byte) numeroMinimoParqueaderos, valorMinimo, valorMaximo)) {
                                listaDeInmueblesQueCumplen.add(esteApartamento);
                            }
                        }
                    }
                }

            } else { //Si es casa lo que se busca
                if (estaUnidad.getNumeroDeCasas() != 0) {
                    for (int j = 0; j < estaUnidad.getListaDeCasas().size(); j++) {
                        Casa estaCasa = estaUnidad.getListaDeCasas().get(j);
                        if (Casa.laCasaAplica(estaCasa, esParaArrendar, areaMinima, areaMaxima,
                                (byte) estratoMinimo, (byte) estratoMaximo, (byte) numeroDeBanhos, (byte) numeroDeEspacios,
                                (byte) numeroMinimoParqueaderos, valorMinimo, valorMaximo)) {
                            listaDeInmueblesQueCumplen.add(estaCasa);
                        }
                    }
                }
            }
        }
        String textoAImprimir = "";

        if (listaDeInmueblesQueCumplen.size() != 0) {

            if (esApartamento) {

                textoAImprimir += "\nLos siguientes apartamentos cumplen con sus criterios de búsqueda:\n\n";

                textoAImprimir += "Código   Dirección          Nombre de la unidad         Torre #   Valor\n";

                textoAImprimir += "-------------------------------------------------------------------------------\n";

                for (int i = 0; i < listaDeInmueblesQueCumplen.size(); i++) {
                    Apartamento esteApartamento = (Apartamento) listaDeInmueblesQueCumplen.get(i);
                    textoAImprimir += esteApartamento.toStringParaBusquedaPorCriterios(esParaArrendar) + "\n";
                }
            } else {
                textoAImprimir += "\nLas siguientes casas cumplen con sus criterios de búsqueda:\n\n";

                textoAImprimir += "Código   Dirección          Nombre de la unidad         Valor\n";

                textoAImprimir += "---------------------------------------------------------------------\n";

                for (int i = 0; i < listaDeInmueblesQueCumplen.size(); i++) {
                    Casa estaCasa = (Casa) listaDeInmueblesQueCumplen.get(i);
                    textoAImprimir += estaCasa.toStringParaBusquedaPorCriterios(esParaArrendar) + "\n";
                }
            }

        } else {
            textoAImprimir += "Ningun" + ((esApartamento) ? " apartamento" : "a casa") + " cumple con sus criterios de búsqueda\n";
        }

        return textoAImprimir;
    }

    public static Object[] obtenerListaDeOpcionesDeUsuario(long cedulaIngresada) throws UsuarioNoEsFuncionarioExcepcion, UsuarioNoExisteExcepcion {

        Persona estaPersona = Persona.buscarPersona(cedulaIngresada);
        if (estaPersona != null) {
            if (estaPersona instanceof Funcionario) {
                LinkedList listaDeOpciones = estaPersona.getMenu().getListaOpciones();
                Object[] opcionesDeMenu = listaDeOpciones.toArray();
                return opcionesDeMenu;
            } else {
                throw new UsuarioNoEsFuncionarioExcepcion();
            }
        } else {
            throw new UsuarioNoExisteExcepcion();
        }

    }

    public static Object[] obtenerListaDeOpcionesPosibles(long cedulaIngresada) throws UsuarioNoEsFuncionarioExcepcion, UsuarioNoExisteExcepcion {
        Persona estaPersona = Persona.buscarPersona(cedulaIngresada);
        if (estaPersona != null) {
            if (estaPersona instanceof Funcionario) {
                MenuDeOpciones menuFull = new MenuDeOpciones(estaPersona.getNivelDeAcceso());
                LinkedList listaDeOpciones = menuFull.getListaOpciones();
                Object[] opcionesDeMenu = listaDeOpciones.toArray();
                return opcionesDeMenu;
            } else {
                throw new UsuarioNoEsFuncionarioExcepcion();
            }
        } else {
            throw new UsuarioNoExisteExcepcion();
        }
    }

    public static void agregarOpcion(long cedula, String nombreOpcionClickeada) {
        Persona estaPersona = Persona.buscarPersona(cedula);
        estaPersona.getMenu().agregarOpcion(nombreOpcionClickeada);
    }

    public static void eliminarOpcion(long cedula, String nombreOpcionClickeada) {
        Persona estaPersona = Persona.buscarPersona(cedula);
        estaPersona.getMenu().eliminarOpcion(nombreOpcionClickeada);
    }

    public static String formatearPrecio(long precio) {
        DecimalFormat formatter = new DecimalFormat("$###,###,###");
        return formatter.format(precio);
    }

    public static String formatearPrecio(float precio) {
        DecimalFormat formatter = new DecimalFormat("$###,###,###");
        return formatter.format(precio);
    }
}
